package com.ruralflow.flow.service.impl;

import java.util.*;

import com.ruralflow.common.exception.ServiceException;
import com.ruralflow.common.utils.DateUtils;
import com.ruralflow.common.utils.SecurityUtils;
import com.ruralflow.common.utils.SequenceUtils;
import com.ruralflow.flow.domain.FlowPass;
import com.ruralflow.flow.domain.vo.FlowApplyApproveReqVO;
import com.ruralflow.flow.enums.FlowApplyApproveStatus;
import com.ruralflow.flow.service.IFlowPassService;
import com.ruralflow.system.service.IActivitiService;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruralflow.flow.mapper.FlowApplyMapper;
import com.ruralflow.flow.domain.FlowApply;
import com.ruralflow.flow.service.IFlowApplyService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 流动申请Service业务层处理
 * 
 * @author ruralflow
 * @date 2025-02-17
 */
@Service
@Slf4j
public class FlowApplyServiceImpl implements IFlowApplyService 
{
    @Autowired
    private FlowApplyMapper flowApplyMapper;

    @Autowired
    private SequenceUtils sequenceUtils;

    @Autowired
    private IActivitiService activitiService;

    @Autowired
    private IFlowPassService flowPassService;

    // 定义支持的流程类型key（字典值）
    private static final Set<String> PROCESS_DEFINITION_KEYS = new HashSet<>();

    static {
        // 目前系统支持的流程类型key
        PROCESS_DEFINITION_KEYS.add("admin");
        PROCESS_DEFINITION_KEYS.add("approve");
    }
    /**
     * 查询流动申请
     * 
     * @param applyId 流动申请主键
     * @return 流动申请
     */
    @Override
    public FlowApply selectFlowApplyByApplyId(Long applyId)
    {
        return flowApplyMapper.selectFlowApplyByApplyId(applyId);
    }

    /**
     * 查询流动申请列表
     * 
     * @param flowApply 流动申请
     * @return 流动申请
     */
    @Override
    public List<FlowApply> selectFlowApplyList(FlowApply flowApply)
    {
        return flowApplyMapper.selectFlowApplyList(flowApply);
    }

    /**
     * 新增流动申请
     * 
     * @param flowApply 流动申请
     * @return 结果
     */
    @Override
    public int insertFlowApply(FlowApply flowApply)
    {
        // 设置基础信息
        flowApply.setCreateTime(DateUtils.getNowDate());
        flowApply.setCreateBy(SecurityUtils.getUsername());
        flowApply.setApplyCode(getNo());

        flowApplyMapper.insertFlowApply(flowApply);

        // 发起审批流程
        ProcessInstance processInstance = startProcess(flowApply);

        if (processInstance != null) {
            String processInstanceId = processInstance.getId();

            /*// 审批启动记录日志信息
            String content = SecurityUtils.getUsername() + "发起审批流程成功";
            contractOperate(contract, ResumeAction.CONTRACT_APPROVAL.getInfo(), content);*/
            log.info("启动流程成功！流程实例ID：{}", processInstanceId);

            // 获取下当前待办任务
            Task task = activitiService.findTask(processInstance.getId());
            // 将流程实例id和审批人写入到表中
            flowApply.setProcessInstanceId(processInstanceId);
            flowApply.setApproveBy(task.getAssignee());

            return flowApplyMapper.updateFlowApply(flowApply);
        }
        return -1;
    }

    /**
     * 修改流动申请
     * 
     * @param flowApply 流动申请
     * @return 结果
     */
    @Override
    public int updateFlowApply(FlowApply flowApply)
    {
        flowApply.setUpdateTime(DateUtils.getNowDate());
        flowApply.setUpdateBy(SecurityUtils.getUsername());
        return flowApplyMapper.updateFlowApply(flowApply);
    }

    /**
     * 批量删除流动申请
     * 
     * @param applyIds 需要删除的流动申请主键
     * @return 结果
     */
    @Override
    public int deleteFlowApplyByApplyIds(Long[] applyIds)
    {
        String updateBy = SecurityUtils.getUsername();
        return flowApplyMapper.deleteFlowApplyByApplyIds(applyIds, updateBy);
    }

    /**
     * 删除流动申请信息
     * 
     * @param applyId 流动申请主键
     * @return 结果
     */
    @Override
    public int deleteFlowApplyByApplyId(Long applyId)
    {
        String updateBy = SecurityUtils.getUsername();
        return flowApplyMapper.deleteFlowApplyByApplyId(applyId, updateBy);
    }

    /**
     * 审批流动申请流程
     * @param flowApplyApproveReqVO 审批参数
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int approveFlowApply(FlowApplyApproveReqVO flowApplyApproveReqVO) {
        // 用户审批结果选择
        String approvalStatus = flowApplyApproveReqVO.getApprovalStatus();

        // 获取流动申请信息
        FlowApply flowApply = flowApplyMapper.selectFlowApplyByApplyId(flowApplyApproveReqVO.getApplyId());
        String processInstanceId = flowApply.getProcessInstanceId();

        // 获取任务信息
        Task task = activitiService.findTask(processInstanceId);

        // 判断当前用户是否允许审批该合同
        if (!task.getAssignee().equals(SecurityUtils.getUsername())) {
            throw new ServiceException("当前用户不是该审批流程的审批人，无法审批");
        }

        // 根据审批结果执行不同操作（操作流程信息），可能会出现空指针异常，正常情况不会有
        handleApproval(flowApplyApproveReqVO, task, processInstanceId);

        // 根据审批结果更新流动申请表信息（记录审批相关信息）
        updateFlowApply(flowApply, processInstanceId, approvalStatus);

        flowApply.setUpdateBy(SecurityUtils.getUsername());
        flowApply.setUpdateTime(DateUtils.getNowDate());

        return flowApplyMapper.updateFlowApply(flowApply);
    }

    @Override
    public Integer selectCountFlowApply() {
        return flowApplyMapper.selectCountFlowApply();
    }

    /**
     * 生成流动申请信息登记编码
     *
     * @return 流动申请信息登记编码
     */
    private String getNo() {
        // 获取用户id补0到五位
        Long userId = SecurityUtils.getUserId();
        String userIdStr = String.format("%05d", userId); // 补零到5位
        return sequenceUtils.createSequenceNumber("FLA" + userIdStr);
    }

    /**
     * 发起审批流程
     *
     * @param flowApply 信息
     * @return ProcessInstance 流程实例对象
     */
    public ProcessInstance startProcess(FlowApply flowApply) {
        // 启动流程实例
        // 取一下唯一一code作为业务关联，方便审批记录表复用
        String businessKey = flowApply.getApplyCode();

        String processDefinitionKey = flowApply.getProcessDefinitionKey();

        if (StringUtils.isBlank(processDefinitionKey)
                || !PROCESS_DEFINITION_KEYS.contains(processDefinitionKey.toLowerCase())) {
            throw new ServiceException("流程类型不合法!");
        }

        Map<String, Object> variables = new HashMap<>();
        // 可以改造这里设置参数
        return activitiService.startProcessInstance(processDefinitionKey, businessKey, variables);
    }

    /**
     * 处理审批结果（处理流程信息）
     */
    private void handleApproval(FlowApplyApproveReqVO flowApplyApproveReqVO, Task task, String processInstanceId) {
        String approvalStatus = flowApplyApproveReqVO.getApprovalStatus();
        if (FlowApplyApproveStatus.AGREE.getCode().equals(approvalStatus)) {
            // 已通过，完成当前节点任务
            Map<String, Object> variables = new HashMap<>();
            activitiService.completeTask(task.getId(), variables);
        } else {
            // 驳回，直接结束整个流程
            activitiService.terminateProcessInstance(processInstanceId);
        }
    }

    /**
     * 根据审批结果更新合同表信息
     */
    private void updateFlowApply(FlowApply flowApply, String processInstanceId, String approvalStatus) {
        // 查询下一个审批任务
        Task task = activitiService.findTask(processInstanceId);
        if (task != null) {
            // 说明有下一个审批人
            flowApply.setApproveBy(task.getAssignee());
        } else {
            // 清空审批人
            flowApply.setApproveBy("");
            // 没有下一个审批人有两种情况（驳回或者正常流程审批结束）
            if (FlowApplyApproveStatus.AGREE.getCode().equals(approvalStatus)) {
                // 设置为审批通过
                flowApply.setApplyStatus("1");
                // 此时调用通行证接口生成一个通行证
                createApplyPass(flowApply);
            } else {
                // 设置为审批不通过
                flowApply.setApplyStatus("2");
            }
        }
    }

    /**
     * 审批提供，根据申请信息生成通行证
     */
    private void createApplyPass(FlowApply flowApply) {
        log.info("审批通过，生成通行证:{}", flowApply);
        FlowPass flowPass = new FlowPass();
/*        Optional.ofNullable(flowApply.getApplyId())
                .ifPresent(flowPass::setApplyId);*/
        // 这个关联键必须有，让他报空指针也行
        flowPass.setApplyId(flowApply.getApplyId());
        Optional.ofNullable(flowApply.getApplyStartTime())
                .ifPresent(flowPass::setPassStartTime);
        Optional.ofNullable(flowApply.getApplyEndTime())
                .ifPresent(flowPass::setPassEndTime);
        // 生成一条通行证信息
        flowPassService.insertFlowPass(flowPass);
    }

}

